<?php
namespace common\service;

use backend\models\AdminUser;
use common\models\ContralSet;
use moonland\phpexcel\Excel;
use Yii;
use yii\helpers\ArrayHelper;

class UtilService {

    /**
     * 生成唯一订单号
     * @return string
     */
    public static function createOrderNumer($len = null) {
        if (empty($len)) {
            $len = 8;
        }
        $order_number = date('YmdHis') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, $len);
        return $order_number;
    }

    /**
     * 获取客户端IP
     * @return string
     */
    public static function  getIp() {
        //判断服务器是否允许$_SERVER
        if (isset($_SERVER)) {
            if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
                $realip = $_SERVER["HTTP_X_FORWARDED_FOR"];
            } elseif (isset($_SERVER["HTTP_CLIENT_IP"])) {
                $realip = $_SERVER["HTTP_CLIENT_IP"];
            } else {
                $realip = $_SERVER["REMOTE_ADDR"];
            }
        } else {
            //不允许就使用getenv获取
            if (getenv("HTTP_X_FORWARDED_FOR")) {
                $realip = getenv("HTTP_X_FORWARDED_FOR");
            } elseif (getenv("HTTP_CLIENT_IP")) {
                $realip = getenv("HTTP_CLIENT_IP");
            } else {
                $realip = getenv("REMOTE_ADDR");
            }
        }

        $realipRs = preg_match("/\,/", $realip);
        if ($realipRs == true) {
            $realipArr = explode(",", $realip);
            $realip    = empty($realipArr[0]) ? $realip : $realipArr[0];
        }

        return $realip;
    }

    /**
     * 获取毫秒级别的时间戳
     * @return array|string
     */
    public static function getMillisecond() {
        //获取毫秒的时间戳
        $time  = explode(" ", microtime());
        $time  = $time[1] . ($time[0] * 1000);
        $time2 = explode(".", $time);
        $time  = $time2[0];
        return $time;
    }

    /**
     * 获取系统参数
     * @return array|mixed|\yii\db\ActiveRecord[]
     */
    public static function getSystemParam() {
        $systemParam = Yii::$app->cache->get("system_param");
        if (!empty($systemParam)) {
            return $systemParam;
        }

        $systemParam = ContralSet::find(["status" => 1])->asArray()->all();
        $systemParam = ArrayHelper::index($systemParam, 'unique_mark');
        if (!empty($systemParam)) {
            try {
                Yii::$app->cache->set('system_param', $systemParam);
            } catch (\Exception $e) {
                $errData = ["msg" => "保存到redis失败", "exception" => $e];
                BaseToolService::error($errData, "UtilService_getSystemParam_error");
            }
        }
        return $systemParam;
    }

    /**
     * 按键值获取参数
     * @param $key
     * @param null $defaultVal
     * @return null|\yii\db\ActiveRecord
     */
    public static function getSystemParamByKey($key, $defaultVal = null) {
        $params = self::getSystemParam();
        if (empty($params[$key]['value'])) {
            return $defaultVal;
        }
        return $params[$key]['value'];
    }

    /**
     * 判断移动设备
     * @return string
     */
    public static function getDeviceType() {
        //全部变成小写字母
        $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
        $type  = 'other';
        //分别进行判断
        if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) {
            $type = 'ios';
        }

        if (strpos($agent, 'android')) {
            $type = 'android';
        }
        return $type;
    }

    public static function convert($size) {
        $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
        return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i];
    }

    /**
     * 获取内存使用量
     * @return string
     */
    public static function getMemoryUsage() {
        return self::convert(memory_get_usage(true));
    }

    /**
     * 签名
     * @param $params
     * @param $key
     * @return string
     */
    public static function getSign($params, $key) {
        ksort($params, SORT_STRING);
        BaseToolService::info($params, "mylog_params");
        $unSignParaString = self::formatQueryParaMap($params, false);
        $unSignParaString = $unSignParaString . "&key=" . $key;
        BaseToolService::info($unSignParaString, "mylog");
        $signStr = sha1($unSignParaString);
        BaseToolService::info($signStr, "mylog_sha");
        return $signStr;
    }

    /**
     * 高德API签名
     * @param $params
     * @param $key
     * @return string
     */
    public static function gdSign($params, $key) {
        ksort($params, SORT_STRING);
        $unSignParaString = self::formatQueryParaMap($params, false);
        $unSignParaString = $unSignParaString . $key;
        BaseToolService::info($unSignParaString, "mylog");
        $signStr = md5($unSignParaString);
        BaseToolService::info($signStr, "mylog");
        return $signStr;
    }

    /**
     * 数组拼接为k=v&k1=v1&k2=v2的形式
     * @param $paraMap
     * @param bool|false $urlEncode
     * @return string
     */
    public static function formatQueryParaMap($paraMap, $urlEncode = false) {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if ($k === "sign") {
                continue;
            }
            if (null !== $v) {
                if (is_array($v)) {
                    $num = 1;
                    foreach ($v as $vArr) {
                        foreach ($vArr as $arrK => $arrV) {
                            $buff .= $k . "{$num}.{$arrK}=" . $arrV . "&";
                        }
                        $num = $num + 1;
                    }
                } else {
                    if($k=="weight"){
                        //float大于5位后,会变成科学记数法,转成正常数字
                        if(false !== stripos($v, "E")){
                            $v = number_format($v,5);
                        }
                    }
                    if ($urlEncode) {
                        $v = urlencode($v);
                    }
                    $buff .= $k . "=" . $v . "&";
                }

            }
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }

    /**
     * 调用高德API获取地址经纬度
     * @param $address
     * @return array
     */
    public static function getLocation($address) {
        if (empty($address)) {
            return ["code" => 400, "msg" => "地址不能为空"];
        }
        $key     = UtilService::getSystemParamByKey("gd_web_api_key");//高德密钥
        $url     = "https://restapi.amap.com/v3/geocode/geo?address={$address}&key={$key}";
        $data    = HttpService::curlGet($url);
        $dataArr = json_decode($data, true);
        if (!empty($dataArr['status']) && $dataArr['status'] == 1) {
            if (empty($dataArr['geocodes'][0]["location"])) {
                return ["code" => 400, "msg" => "无返回经纬度"];
            } else {
                $location = $dataArr['geocodes'][0]["location"];
                $arr      = explode(",", $location);
                $logitude = empty($arr[0]) ? null : $arr[0];
                $latiude  = empty($arr[1]) ? null : $arr[1];
                if ($logitude == null || $latiude == null) {
                    return ["code" => 400, "msg" => "经度{$logitude}或纬度{$latiude}有一个为空"];
                }
                return ["code" => 200, "logitude" => $logitude, "latiude" => $latiude];
            }
        } else {
            return ["code" => 400, "msg" => "调用高德API失败"];
        }
    }

    /**
     * 计算两组经纬度坐标 之间的距离
     * params ：lat1 纬度1； lng1 经度1； lat2 纬度2； lng2 经度2； len_type （1:m or 2:km);
     * @param $lat1
     * @param $lng1
     * @param $lat2
     * @param $lng2
     * @param int $len_type
     * @param int $decimal
     * @return float
     */
//    public static function getDistance($lat1, $lng1, $lat2, $lng2, $len_type = 1, $decimal = 2) {
////        define('PI',3.1415926535898);
////        define('EARTH_RADIUS',6378.137);
//        $pi = 3.1415926535898 ;
//        $earth_radius = 6378.137 ;
//        $radLat1 = $lat1 * $pi / 180.0;
//        $radLat2 = $lat2 * $pi / 180.0;
//        $a = $radLat1 - $radLat2;
//        $b = ($lng1 * $pi / 180.0) - ($lng2 * $pi / 180.0);
//        $s = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1) * cos($radLat2) * pow(sin($b/2),2)));
//        $s = $s * $earth_radius;
//        $s = round($s * 1000);
//        if ($len_type > 1)
//        {
//            $s /= 1000;
//        }
//        return round($s, $decimal);
//    }


    /**
     * 调用高德API获取骑行距离
     * params ：lat1 纬度1； lng1 经度1； lat2 纬度2； lng2 经度2； len_type （1:m or 2:km);
     * @param $address
     * @return array
     */
    public static function getDistance($lat1, $lng1, $lat2, $lng2, $decimal = 2) {
        if (empty($lng1) || empty($lat1) || empty($lng2) || empty($lng2)) {
            return ["code" => 400, "msg" => "经纬度不能为空"];
        }
        $storeLocation = "{$lng1},{$lat1}";
        $destLocation  = "{$lng2},{$lat2}";
        $key           = UtilService::getSystemParamByKey("gd_web_api_key");//高德密钥
        $url           = "https://restapi.amap.com/v4/direction/bicycling?origin={$storeLocation}&destination={$destLocation}&key={$key}";
        BaseToolService::info($url, "mylog");
        $data    = HttpService::curlGet($url);
        $dataArr = json_decode($data, true);
        if ($dataArr['errcode'] === 0) {
            if (isset($dataArr['data']['paths'][0]["distance"]) == false) {
                return ["code" => 400, "msg" => "无返回骑行距离"];
            } else {
                $distance = $dataArr['data']['paths'][0]["distance"];
                return ["code" => 200, "distance" => $distance];
            }
        } else {
            $errmsg = empty($dataArr['errdetail']) ? "失败" : $dataArr['errdetail'];
            return ["code" => 400, "msg" => "调用高德API失败,原因:" . $errmsg];
        }
    }

    /**
     * 验证身份证
     * @param $id
     * @return bool
     */
    public static function isIdCard($id) {
        $id        = strtoupper($id);
        $regx      = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/";
        $arr_split = array();
        if (!preg_match($regx, $id)) {
            return FALSE;
        }
        if (15 == strlen($id)) //检查15位
        {
            $regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/";

            @preg_match($regx, $id, $arr_split);
            //检查生日日期是否正确
            $dtm_birth = "19" . $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
            if (!strtotime($dtm_birth)) {
                return FALSE;
            } else {
                return TRUE;
            }
        } else      //检查18位
        {
            $regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/";
            @preg_match($regx, $id, $arr_split);
            $dtm_birth = $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
            if (!strtotime($dtm_birth)) //检查生日日期是否正确
            {
                return FALSE;
            } else {
                //检验18位身份证的校验码是否正确。
                //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。
                $arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
                $arr_ch  = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
                $sign    = 0;
                for ($i = 0; $i < 17; $i++) {
                    $b = (int)$id{$i};
                    $w = $arr_int[$i];
                    $sign += $b * $w;
                }
                $n       = $sign % 11;
                $val_num = $arr_ch[$n];
                if ($val_num != substr($id, 17, 1)) {
                    return FALSE;
                } //phpfensi.com
                else {
                    return TRUE;
                }
            }
        }

    }

    /**
     * 生成用户token 组成方式 userId|Y-m-d H:i:s
     */
    public static function createToken($storeCode, $userId) {
        $curDate  = date("Y-m-d H:i:s");
        $tokenStr = "{$userId}|{$curDate}|{$storeCode}";

        $seceryKey = self::getSystemParamByKey("hq_key");//鸿桥密钥
        $encry     = new Encrypt3DesService($seceryKey, true);
        $token     = $encry->encrypt($tokenStr);
        return $token;
    }

    /**
     * 通过TOKEN获取用户
     * @param $token
     * @return array
     */
    public static function  getUserByToken($token) {
        $seceryKey = self::getSystemParamByKey("hq_key");//鸿桥密钥
        $encry     = new Encrypt3DesService($seceryKey, true);
        $str       = $encry->decrypt($token);
        if (empty($str)) {
            return ["code" => 400, "msg" => "无法解密token"];
        }
        $strArr = explode("|", $str);
        if (empty($strArr[0])) {
            return ["code" => 400, "msg" => "无法获取userId"];
        }
        if (empty($strArr[2])) {
            return ["code" => 400, "msg" => "无法获取门店"];
        }

        $user = AdminUser::findOne(["user_id" => $strArr[0]]);
        if (empty($user)) {
            return ["code" => 400, "msg" => "用户不存在"];
        }
//        $rs = Yii::$app->user->login($user,  3600);
//        $session = Yii::$app->session ;
//        $session->set('user_store_code',$strArr[2]);
        return ["code" => 200, "data" => ["user" => $user, "store_code" => $strArr[2]]];
    }

    /**
     * 导入EXCEL
     * @param $filename
     * @return string
     */
    public static function importExcel($filename, $sheetName = null) {
        if (empty($sheetName)) {
            $sheetName = 'Sheet1';
        }
        $data = Excel::widget([
            'mode'                 => 'import',
            'fileName'             => $filename,
            'setFirstRecordAsKeys' => false,
            'setIndexSheetByName'  => true,
            'getOnlySheet'         => $sheetName,
        ]);
        return $data;
    }

    /**
     * 获取小数位
     * @param $num
     * @return int
     */
    public static function getFloatLength($num) {
        $count = 0;

        $temp = explode('.', $num);

        if (sizeof($temp) > 1) {
            $decimal = end($temp);
            $count   = strlen($decimal);
        }
        return $count;

    }

    /**
     * 判断是不是手机
     * @return int
     */
    public static function isMobile(){
        $useragent = $_SERVER['HTTP_USER_AGENT'];
        if (preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i', $useragent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',
                substr($useragent, 0, 4))) {
            // 手机
            return true;
        } else {
            // 电脑
            return false;
        }
    }


//    public static function sctonum($num, $double = 5){
//        if(false !== stripos($num, "e")){
//            $a = explode("e",strtolower($num));
//            return bcmul($a[0], bcpow(10, $a[1], $double), $double);
//        }
//    }

}